/**
 *  Copyright 2011 Ryszard Wiśniewski <brut.alll@gmail.com>
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package brut.androlib.res.decoder;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Logger;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.wrapper.XmlPullParserWrapper;
import org.xmlpull.v1.wrapper.XmlPullWrapperFactory;
import org.xmlpull.v1.wrapper.XmlSerializerWrapper;
import org.xmlpull.v1.wrapper.classic.StaticXmlSerializerWrapper;

import brut.androlib.AndrolibException;
import brut.androlib.res.data.ResTable;
import brut.androlib.res.util.ExtXmlSerializer;

/**
 * @author Ryszard Wiśniewski <brut.alll@gmail.com>
 */
public class XmlPullStreamDecoder implements ResStreamDecoder {
    public XmlPullStreamDecoder(XmlPullParser parser,
            ExtXmlSerializer serializer) {
        this.mParser = parser;
        this.mSerial = serializer;
    }

    public void decode(InputStream in, OutputStream out)
            throws AndrolibException {
        try {
            XmlPullWrapperFactory factory = XmlPullWrapperFactory.newInstance();
            XmlPullParserWrapper par = factory.newPullParserWrapper(mParser);
            final ResTable resTable = ((AXmlResourceParser)mParser).getAttrDecoder().getCurrentPackage().getResTable();
            
            XmlSerializerWrapper ser = new StaticXmlSerializerWrapper(mSerial, factory){
                boolean hideSdkInfo = false;
                boolean hidePackageInfo = false;
                @Override
                public void event(XmlPullParser pp) throws XmlPullParserException, IOException {
                    int type = pp.getEventType();
                    
                        if (type == XmlPullParser.START_TAG) {
                        	if ("manifest".equalsIgnoreCase(pp.getName())) {
                        		try {
									hidePackageInfo = parseManifest(pp);
								} catch (AndrolibException e) {}
                        	}else if ("uses-sdk".equalsIgnoreCase(pp.getName())) {
                                try {
                                    hideSdkInfo = parseAttr(pp);
                                    if(hideSdkInfo) {
                                    	return;                               
                                    }
                                } catch (AndrolibException e) {}
                            }
                        } else if (hideSdkInfo && type == XmlPullParser.END_TAG && 
                                	"uses-sdk".equalsIgnoreCase(pp.getName())) {
                        	return;
                        } else if (hidePackageInfo && type == XmlPullParser.END_TAG &&
                                	"manifest".equalsIgnoreCase(pp.getName())) {
                        	super.event(pp);
                            return;
                        }
                        super.event(pp);
                    }
                
                private boolean parseManifest(XmlPullParser pp) throws AndrolibException {
                	ResTable restable = resTable;
                	
                	// read <manifest> for package:
                	for (int i = 0; i < pp.getAttributeCount(); i++) {
                		if (pp.getAttributeName(i).equalsIgnoreCase(("package"))) {
                			restable.addPackageInfo("orig_package", pp.getAttributeValue(i));
                		}
                	}
                	return true;
                }
                
                private boolean parseAttr(XmlPullParser pp) throws AndrolibException {
                    ResTable restable = resTable;
                    for (int i = 0; i < pp.getAttributeCount(); i++) {
                        final String a_ns = "http://schemas.android.com/apk/res/android";
                        String ns = pp.getAttributeNamespace (i);
                                                
                        if (a_ns.equalsIgnoreCase(ns)) {
                            String name = pp.getAttributeName (i);
                            String value = pp.getAttributeValue (i);
                            if (name != null && value != null) {
                                if (name.equalsIgnoreCase("minSdkVersion") || 
                                        name.equalsIgnoreCase("targetSdkVersion") || 
                                        name.equalsIgnoreCase("maxSdkVersion")) {
                                    restable.addSdkInfo(name, value);
                                } else {
                                    restable.clearSdkInfo();
                                    return false;//Found unknown flags
                                }
                            }
                        } else {
                            resTable.clearSdkInfo();
                            
                            if (i >= pp.getAttributeCount()) {
                            	return false;//Found unknown flags
                            }
                        }
                    }
                    return true;
                }
            };

            par.setInput(in, null);
            ser.setOutput(out, null);

            while (par.nextToken() != XmlPullParser.END_DOCUMENT) {
                ser.event(par);
            }
            ser.flush();
        } catch (XmlPullParserException ex) {
            throw new AndrolibException("Could not decode XML", ex);
        } catch (IOException ex) {
            throw new AndrolibException("Could not decode XML", ex);
        }
    }

    public void decodeManifest(InputStream in, OutputStream out)
            throws AndrolibException {
        mOptimizeForManifest = true;
        try {
            decode(in, out);
        } finally {
            mOptimizeForManifest = false;
        }
    }

    private final XmlPullParser mParser;
    private final ExtXmlSerializer mSerial;

    private boolean mOptimizeForManifest = false;

    private final static Logger LOGGER =
        Logger.getLogger(XmlPullStreamDecoder.class.getName());
}
